#!/usr/bin/env python

# Python Oracle VM Server Management
#
# Copyright (C) 2011 ovm Project
# Author: Choonho Son <choonho@kt.com>
# URL: <http://ovm.googlecode.com>
# For license information, see LICENSE.TXT
#


__author__    = "Choonho son"
__copyright__ = "Copyrought 2011, OVM Project"
__license__   = "BSD"
__version__   = "1.0"
__maintainer__ = "Choonho Son"
__email__     = "choonho@kt.com"
__status__    = "Stable"

from utils.Command import *
from utils.ipaddr import *

import sys
import socket
import traceback
from sets import Set
from optparse import OptionParser
from ConfigParser import ConfigParser
import urllib
from os.path import exists

command = Command()

def getPartitions():
    """
    @return : partition list
    find current partitions in /proc/partitions
    """
    fp = open("/proc/partitions")
    partitions = []
    for line in fp:
        part = re.findall(r'(\w+)', line)
        if len(part) != 4: continue
        if part[3] != "name":
            partitions.append(part[3])

    return Set(partitions)

                                  
def find_session():
    """
    @return : current iSCSI seesion (portal, target)
    """
    cmd = "iscsiadm -m session"
    session = []
    try:
        rcode = command.execute(cmd)
        if len(rcode[1]) > 0: raise CmdError(rcode[1])
        for line in rcode[0].split("\n"):
            elements = line.split(" ")
            if elements[0] != "tcp:": continue

            (ip_ports,extra) = elements[2].split(",")
            (ip,port) = ip_ports.split(":")
            session.append( (ip,elements[3]) )
                
    except CmdError, e:
        print "CmdError"
        print e
        # may be -> no active sessions.
        return rcode[1]
            
    except:
        print "#### Unknown Error ####"
        print traceback.print_exc()
        sys.exit()

    return session

def discovery(portal):
    """
    @param portal : portal IP address
    @return : IQNs
    find iSCSI IQNs
    """
    cmd = "iscsiadm -m discovery -t sendtargets -p %s" % portal
    iqns = []
    try:
        rcode = command.execute(cmd)
        if len(rcode[1]) > 0: raise CmdError(rcode[1])

        #result look like
        #10.1.1.250:3260,2 iqn.1986-03.com.sun:02:309267fe-7244-c8f6-fa06-a189b0bfb4a7
        for line in rcode[0].split("\n"):
            items = line.split(" ")
            if len(items) == 2:
                portal = (items[0].split(","))[0]
                iqn = items[1]
                iqns.append( (portal,iqn) )

        return iqns
        
    except CmdError, e:
        print e
        return False

    except:
        print "#### Unknown Error ####"
        print traceback.print_exc()
        return False
        

def findDevByLun(lun_num):
    """
    @param lun_num : LUN number
    @return : device name
    """
    cmd = "iscsiadm -m session -P 3"
    try:
        rcode = command.execute(cmd)
        if len(rcode[1]) > 0: raise CmdError(rcode[1])
        pattern_lun = r'(Lun: (\d+))'
        pattern_dsk = r'(Attached scsi disk (\w+))'

        lun = -1
        dsk = None
        disks = {}
        for line in rcode[0].split("\n"):
            #first find pattern_lun
            result1 = re.findall(pattern_lun, line)
            if len(result1) > 0:
                # result: [('Lun: 10', 'Lun:', '10')]
                lun = int(result1[0][1])

            result2 = re.findall(pattern_dsk, line)
            if len(result2) > 0:
                #[('Attached scsi disk sdd', 'sdd')]
                dsk = result2[0][1]
                if lun > 0 and dsk != None:
                    disks[lun] = dsk
                    lun = -1
                    disk = None

        if disks.has_key(lun_num):            
            return disks[lun_num]
        else:
            return False

    except:
        return False

def login(target,portal,method="login"):
    """
    @param target : iqn
    @return :True if Success
    iscsi login with target iqn
    """

    cmd = "iscsiadm --mode node --target %s --portal %s --%s" % (target, portal,method)
        
    try:
        rcode = command.execute(cmd)
        if len(rcode[1]) > 0: raise CmdError(rcode[1])
        return True
    except CmdError, e:
        print e
        sys.exit()
    except:
        print "### Unknown Error ###"
        print traceback.print_exc()
        sys.exit()

def logout(target,portal,method="logout"):
    return login(target,portal,method)

def logout_all():
    iqns = find_session()
    if iqns == False:
        return "[Error] There is no iscsi Sesession"

    print iqns
    for (portal, target) in iqns:
        logout(target, portal)
    return True
    
def console(answer):
    #iSCSI connection logic
    #Make iSCSI instance
    portal = None
    if answer.has_option("portal","ip"):
        portal = answer.get("portal","ip")
    else:
        while portal == None:
            ip_str = raw_input("Input iSCSI portal IP> ")
            if isIPaddr(ip_str):
                portal = ip_str
                break
            else:
                print "Invalid IP format"

    # find iSCSI session
    iqns = discovery(portal)
    if iqns == False:
        print "iSCSI target is not discovered"
        sys.exit()

    #############    
    # Login
    # iSCSI login
    #
    req_iqn = None
    my_hostname = socket.gethostname()
    if answer.has_option("iqn",my_hostname) == True:
        req_iqn = answer.get("iqn",my_hostname)
        
    # check 
    count = 0
    selected = False
    for item in iqns:
        print "%s) %s %s" % (count,item[0],item[1])
        if req_iqn == item[1]:
            choice = count
            selected = True
        count = count + 1

    if selected == False:    
        choice = raw_input("select iqn #> ")
        
    (portal, target) = iqns[int(choice)]
    login(target,portal)

    print "================= Login IQN ======================="
    print target

if __name__ == "__main__":
    parser = OptionParser()
    parser.add_option("-a","--answer", dest="answer", help="path to Answer file")
    parser.add_option("-m","--method", dest="method", help="[login|logout|dev]")
    parser.add_option("-l","--lun", dest="lun", help="find device by Lun #")
    (options, args) = parser.parse_args()
    if options.method == "login":
        if options.answer:
            answer = ConfigParser()
            if exists(options.answer):
                # Local file
                answer.readfp( open(options.answer) )
            else:
                # url
                fp = urllib.urlopen(options.answer)
                temp = open("/tmp/_iscsi_answer",'w')
                temp.write(fp.read())
                temp.close()
                answer.readfp( open("/tmp/_iscsi_answer") )
        else:
            answer = ConfigParser()

        console(answer)

    if options.method == "logout":
       	logout_all()
       

    if options.method == "dev" and int(options.lun) > 0:
       	print findDevByLun(int(options.lun))

